<template>
  <el-form
    :id="componentId"
    ref="ruleForms"
    :model="ruleForm"
    :rules="rules"
    :label-width="formConfig.labelWidth || '100px'"
    :validate-on-rule-change="false"
  >
    <el-row class="flex" style="flex-wrap: wrap">
      <el-col
        v-for="(item, index) in filterFormColumns(formColumns)"
        :span="item.span ? item.span : 24"
        :key="index"
        :style="item.layoutStyle"
      >
        <el-form-item
          :label="item.label || ''"
          :prop="item.prop && item.prop"
          :style="item.style"
          :rules="item.rules && item.rules"
          v-if="!item.isShow"
        >
          <!-- 输入框 -->
          <el-input
            v-if="item.type === 'Input'"
            type="input"
            v-model="ruleForm[item.prop]"
            :placeholder="item.placeholder || `请输入${item.label || ''}`"
            :maxlength="item.maxlength"
            :readonly="item.readonly || false"
            :disabled="item.disabled"
            @change="(val) => handleChange(val, item, ruleForm)"
            autocomplete="off"
            clearable
          >
          </el-input>
          <el-input
            v-if="item.type === 'Password'"
            type="password"
            v-model.trim="ruleForm[item.prop]"
            :placeholder="item.placeholder || `请输入${item.label || ''}`"
            :maxlength="item.maxlength"
            :readonly="item.readonly || false"
            :disabled="item.disabled"
            @change="(val) => handleChange(val, item, ruleForm)"
            autocomplete="off"
            clearable
          >
          </el-input>
          <el-input
            v-if="item.type === 'Textarea'"
            type="textarea"
            v-model="ruleForm[item.prop]"
            :rows="item.rows || 3"
            :placeholder="item.placeholder || `请输入${item.label || ''}`"
            :maxlength="item.maxlength"
            :readonly="item.readonly || false"
            :disabled="item.disabled"
            @change="(val) => handleChange(val, item, ruleForm)"
            show-word-limit
            clearable
          >
          </el-input>
          <el-input-number
            v-if="item.type === 'InputNumber'"
            v-model="ruleForm[item.prop]"
            :min="item.min"
            :max="item.max"
            :step="item.step"
            step-strictly
          ></el-input-number>
          <!-- 下拉选择 / 多选 / 单选 -->
          <el-select
            v-if="item.type === 'Select'"
            v-model="ruleForm[item.prop]"
            style="width: 100%"
            :multiple="item.multiple"
            :placeholder="`请选择${item.label || ''}`"
            @change="(val) => handleChange(val, item, ruleForm)"
            :disabled="item.disabled"
            filterable
            clearable
          >
            <el-option
              v-for="(option, idx) in item.options"
              :key="idx"
              :label="option[item.optionConfig.label]"
              :value="option[item.optionConfig.value]"
            >
              <template v-if="item.optionConfig.autoDefinedIcon">
                <i
                  :class="option[item.optionConfig.value]"
                  style="margin-right: 5px"
                ></i>
                <span>{{ option[item.optionConfig.label] }}</span>
              </template>
            </el-option>
          </el-select>
          <!-- Radio -->
          <el-radio-group
            v-if="item.type === 'Radio'"
            v-model="ruleForm[item.prop]"
            :disabled="item.disabled"
            @change="(val) => handleChange(val, item, ruleForm)"
          >
            <el-radio
              v-for="(radio, idx) in item.options"
              :key="idx"
              :label="radio[item.optionConfig.value]"
              >{{ radio[item.optionConfig.label] }}</el-radio
            >
          </el-radio-group>
          <!-- Checkbox -->
          <el-checkbox-group
            v-if="item.type === 'Checkbox'"
            v-model="ruleForm[item.prop]"
            @change="(val) => handleChange(val, item, ruleForm)"
          >
            <el-checkbox
              v-for="(check, idx) in item.options"
              :key="idx"
              :label="check[item.optionConfig.value]"
              >{{ check[item.optionConfig.label] }}
            </el-checkbox>
          </el-checkbox-group>
          <!-- Cascader -->
          <el-cascader
            v-if="item.type === 'Cascader'"
            v-model="ruleForm[item.prop]"
            :options="item.options"
            :props="{
              label: item.optionConfig.label,
              value: item.optionConfig.value,
              children: item.optionConfig.children || 'children',
              checkStrictly: item.optionConfig.checkStrictly || true,
            }"
            :placeholder="`请选择${item.label}`"
            @change="(val) => handleChange(val, item, ruleForm)"
            filterable
            clearable
          >
          </el-cascader>
          <!-- 日期选择器 -->
          <el-date-picker
            v-if="item.type === 'Date'"
            v-model="ruleForm[item.prop]"
            type="date"
            style="width: 100%"
            value-format="timestamp"
            placeholder="选择日期"
            :disabled="item.disabled"
            clearable
          />
          <!-- 日期时间选择器 -->
          <el-date-picker
            v-if="item.type === 'DateTime'"
            v-model="ruleForm[item.prop]"
            type="datetime"
            style="width: 100%"
            value-format="timestamp"
            placeholder="选择日期时间"
            :disabled="item.disabled"
            clearable
          />
          <!-- 日期范围 -->
          <el-date-picker
            v-if="item.type === 'DateRange'"
            v-model="ruleForm[item.prop]"
            type="daterange"
            range-separator="至"
            :start-placeholder="item.placeholder[0]"
            :end-placeholder="item.placeholder[1]"
            style="width: 100%"
            value-format="yyyy-MM-dd HH:mm:ss"
            :default-time="['00:00:00', '23:59:59']"
            :disabled="item.disabled"
            clearable
          />
          <!-- 日期时间范围 -->
          <el-date-picker
            v-if="item.type === 'DatetimeRange'"
            v-model="ruleForm[item.prop]"
            type="datetimerange"
            range-separator="至"
            :start-placeholder="item.placeholder[0]"
            :end-placeholder="item.placeholder[1]"
            style="width: 100%"
            value-format="yyyy-MM-dd HH:mm:ss"
            :disabled="item.disabled"
            clearable
          />
          <!-- Slot -->
          <template v-if="item.type === 'Slot'">
            <slot :name="item.slotName || ''" :form="ruleForm"></slot>
          </template>
          <!-- Render -->
          <template v-if="item.type === 'Render'">
            <render :render="item.render" :item="item" :form="ruleForm" />
          </template>
        </el-form-item>
      </el-col>
    </el-row>
  </el-form>
</template>
<script lang="ts">
import { defineComponent, reactive, ref, toRef,toRefs } from "vue";
interface ObjData {
  [key: string]: any;
}
export default defineComponent({
  props: {
    formConfig: {
      required: true,
      type: Object,
      default: () => ({
        // 基础配置相关
        // eslint-disable-next-line object-property-newline
        span: 24,
        labelWidth: "100px",
        // info查询相关
        infoParams: null, // info 查询参数|接收的数据 { userId: '123' }
        infoMethod: null, // info 查询方法
        infoCallback: null, // info 查询回调
        // submit提交相关
        submitMethod: null, // 表单提交方法
        submitCallback: null, // 表单提交回调

        submit: null, // 自定义提交表单

        // reset重置相关
        reset: null, // 自定义重置表单
      }),
    },
    formColumns: {
      required: true,
      type: Array,
      default: () => [],
    },
  },
  components: {
    // render
    render: {
      props: {
        render: "",
        item: "",
        form: "",
      },
      render(h: any) {
        const params = this.item;
        const parent = this.form;
        return this.render(h, params, parent);
      },
    },
  },
  emits: ["pageChanged", "refresh"],
  setup(props) {
    const componentId = ref(
      `form-${Date.now()}${Math.floor(Math.random() * 1000)}`
    );
    const dataList = reactive({
      ruleForm: {} as any,
      rules: {} as any,
      filterProps: [] as any, // 提交时，过滤不用提交的参数
    });
    const ruleForms = ref(null);
    const formColumns = toRef(props, "formColumns");
    const formConfig = toRef(props, "formConfig");
    const data = reactive({ 
      name:''
    });
    // 过滤 显示 el-form-item 项
    const filterFormColumns = (columns: any[]) => {
      return columns.filter((item) => {
        if (typeof item.isShow === "function") {
          return item.isShow();
        }
        return true;
      });
    };
    // 初始化 表单
    const initForm = () => {
      const form: ObjData = {};
      const rules: ObjData = {};
      dataList.filterProps = [];

      formColumns.value.forEach((item: any) => {
        // 表单初始化
        if (
          ["Checkbox", "DateRange", "DatetimeRange"].includes(item.type) &&
          item.prop
        ) {
          form[item.prop] = [];
        } else {
          item.prop && (form[item.prop] = "");
        }

        // 如果有 初始值，赋上 初始值
        if (item.initValue !== undefined && item.prop) {
          form[item.prop] = item.initValue;
        }

        if (["Radio", "Checkbox", "Select", "Cascader"].includes(item.type)) {
          // 如果 自定义了 optionConfig
          if (item.optionConfig && Object.keys(item.optionConfig).length > 0) {
            const { method, params } = item.optionConfig;
            method &&
              method(params).then((res = []) => {
                // eslint-disable-next-line no-param-reassign
                item.options = res;
              });
          }
          // 默认 使用 options 里的 label 和 value
          else {
            // eslint-disable-next-line no-param-reassign
            item.optionConfig = {
              label: "label",
              value: "value",
            };
          }
        }

        // 收集 Render 类型的 prop，提交表单时过滤
        if (item.type === "Render" && item.prop && !item.need) {
          dataList.filterProps.push(item.prop);
        }

        // 必填项
        if (item.required && item.prop) {
          if (
            ["Input", "InputNumber", "Password", "Textarea"].includes(item.type)
          ) {
            rules[item.prop] = [
              {
                required: true,
                message: item.placeholder
                  ? item.placeholder
                  : `请输入${item.label || ""}`,
                trigger: "blur",
              },
            ];
          }
          if (
            [
              "Select",
              "Radio",
              "Checkbox",
              "DatePicker",
              "DateTimePicker",
              "DateRange",
              "DatetimeRange",
            ].includes(item.type)
          ) {
            rules[item.prop] = [
              {
                required: true,
                message: item.placeholder
                  ? item.placeholder
                  : `请选择${item.label || ""}`,
                trigger: "blur, change",
              },
            ];
          }
        }
      });

      dataList.ruleForm = form;
      dataList.rules = rules;
    };
    // 赋值 表单
    const assignForm = async (infoParams = {}) => {
      Object.assign(dataList.ruleForm, infoParams);
      // 将 infoParams 置空
      // eslint-disable-next-line vue/no-mutating-props
      formConfig.value.infoParams = null;

      let result = {} as any;
      if (formConfig.value.infoMethod) {
        result = await formConfig.value.infoMethod(infoParams);
      } else {
        result = infoParams;
      }

      // 联动 赋值 options
      formConfig.value.forEach(
        (item: { changeCallback: any; prop: string | number }) => {
          if (item.changeCallback) {
            assignRelatedOptions(item, result[item.prop]);
          }
        }
      );

      for (const item in dataList.ruleForm) {
        if (/^\[.*\]$/.test(item)) {
          JSON.parse(item).forEach((kk: string | number) =>
            dataList.ruleForm[item].push(result[kk])
          );
        } else {
          (result[item] || result[item] === 0) &&
            (dataList.ruleForm[item] = result[item]);
        }
      }
      formConfig.value.infoCallback && formConfig.value.infoCallback(result);
    };
    // 联动 拉取 options 数据
    const assignRelatedOptions = (
      item: { changeCallback: any; prop?: string | number; optionConfig?: any },
      value: any
    ) => {
      // if (Array.isArray(item.changeCallback)) {
      //   item.changeCallback.forEach((it) => {
      //     const { prop, method } = it;
      //     dataList.ruleForm[prop] = "";
      //     if (value) {
      //       method({ [item.optionConfig.value]: value }).then((res = []) => {
      //         // eslint-disable-next-line no-shadow
      //         const idx = formColumns.value.findIndex(
      //           (it: any) => it.prop === prop
      //         );
      //         // eslint-disable-next-line vue/no-mutating-props
      //         formColumns.value[idx].options = res;
      //       });
      //     }
      //   });
      // } else {
      //   const { prop, method } = item.changeCallback;
      //   dataList.ruleForm[prop] = "";
      //   if (value) {
      //     method({ [item.optionConfig.value]: value }).then((res = []) => {
      //       const idx = formColumns.value.findIndex(
      //         (it: any) => it.prop === prop
      //       );
      //       // eslint-disable-next-line vue/no-mutating-props
      //       formColumns.value[idx].options = res;
      //     });
      //   }
      // }
    };
    // 统一 处理选择事件
    const handleChange = (
      val: any,
      item: {
        change?: any;
        changeCallback: any;
        prop?: string | number | undefined;
        optionConfig?: any;
      },
      ruleForm: any
    ) => {
      if (typeof item.change === "function") {
        item.change(val, item, ruleForm);
      }
      // 如果有 change 联动
      if (item.changeCallback) {
        assignRelatedOptions(item, val);
      }
    };
    /**
     * 将 slot 里的参数传进来
     * @param {*} params      补充 ruleForm 属性
     * @param {*} filterKeys  提交 ruleForm 时需要过滤的属性
     */
    const handleFormParams = (params = {}, filterKeys = []) => {
      dataList.ruleForm = Object.assign({}, dataList.ruleForm, params);
      filterKeys.forEach(
        (key) =>
          !dataList.filterProps.includes(key) && dataList.filterProps.push(key)
      );
    };
    // 过滤提交 null 值
   const onSubmit = () => {
      (ruleForms.value as any).validate((valid: any) => {
        if (valid) {
          // 过滤对象为 null 的属性
          const params = {} as any;
          for (const key in dataList.ruleForm) {
            if (
              dataList.ruleForm[key] !== null &&
              !dataList.filterProps.includes(key)
            ) {
              if (/^\[.*\]$/.test(key)) {
                JSON.parse(key).forEach(
                  (kk: string | number, ii: string | number) => {
                    params[kk] = dataList.ruleForm[key][ii];
                  }
                );
              } else {
                params[key] = dataList.ruleForm[key];
              }
            }
          }
          return params;
        } else {
          return false;
        }
     });
    };
    return {
      ...toRefs(data),
      componentId,
      filterFormColumns,
      initForm,
      assignForm,
      handleChange,
      ruleForms,
      handleFormParams,
      onSubmit,
    };
  },
});
</script>
<style lang="scss" scoped>
::v-deep .el-tag {
  max-width: 100%;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}
</style>
